/////////////////////////////////////////////////////////////////////
//
//  MOE Framework (Meta Object Encapsulation Framework)
//
//  Original Author: Wiksy Wang, 2011
//
/////////////////////////////////////////////////////////////////////

#ifndef MOE_ASSIGN_VALUE_HPP
#define MOE_ASSIGN_VALUE_HPP

#include "AssignProxy.hpp"
#include "../ObjectTypeManager.h"
#include "../RawByteVector.h"

namespace MOE
{

namespace Assign
{

namespace Functors
{

// TODO: This can be optimized so that value members can share the same struct and use different functions.
// DataMemberMeta class may be changed to support this better.

template <class T, class FieldType>
struct ValueGet
{
	ValueGet(FieldType T::* field)
		: _fieldAddr(field)
	{
	}

	void operator() (void* object, void* pData)
	{
		*static_cast<FieldType*>(pData) = static_cast<T*>(object)->*_fieldAddr;
	}

private:
	FieldType T::* _fieldAddr;
};

template <class T, class FieldType>
struct ValueSet
{
	ValueSet(FieldType T::* field)
		: _fieldAddr(field)
	{
	}

	void operator() (void* object, const void* pData)
	{
		static_cast<T*>(object)->*_fieldAddr = *static_cast<const FieldType*>(pData);
	}

private:
	FieldType T::* _fieldAddr;
};

template <class T, class FieldType>
struct ValueAccess
{
	ValueAccess(FieldType T::* field)
		: _fieldAddr(field)
	{
	}

	void* operator() (void* object)
	{
		return &(static_cast<T*>(object)->*_fieldAddr);
	}

private:
	FieldType T::* _fieldAddr;
};

}

template <class T, class FieldType>
AssignProxy Value(const RawByteVector& name, FieldType T::* field)
{
	return AssignProxy(
		name,
		DataMemberMeta(ObjectTypeManager::GetClassID<FieldType>())
			.DefineGetter(Functors::ValueGet<T, FieldType>(field))
			.DefineSetter(Functors::ValueSet<T, FieldType>(field))
			.DefineDirectAccessor(Functors::ValueAccess<T, FieldType>(field))
		);
}

}

}

#endif
